﻿#ifndef _IPV4_H_
#define _IPV4_H_

#include <stdint.h>
#include "net_err.h"
#include "ncfg.h"
#include "netif.h"
#include "pktbuf.h"

#define NET_VERSION_IPV4 4

#pragma pack(1)

// ipv4 报文头结构
typedef struct _ipv4_hdr_t
{
// version: 版本 shdr: 头部长度 tos: 优先级和服务类型
// 解决大小端的格式问题
#if NET_ENDIAN_LITTLE
    union
    {
        struct
        {
            uint16_t shdr : 4;
            uint16_t version : 4; // 单位4字节,报文头长度
            uint16_t tos : 8;
        };
        uint16_t shdr_all;
    };
#else
    union
    {
        struct
        {
            uint16_t version : 4;
            uint16_t shdr : 4; // 单位4字节,报文头长度
            uint16_t tos : 8;
        };
        uint16_t shdr_all;
    };
#endif
    uint16_t total_len; // 总长度,单位字节
    uint16_t id;        //

#if NET_ENDIAN_LITTLE
    union
    {
        struct
        {
            uint16_t offset : 13; // 分片数据包的偏移量,单位8字节
            uint16_t more : 1;    // 后面有无其他分片包
            uint16_t disable : 1; // 是否允许分片
            uint16_t reverse : 1; // 保留位,固定值为0
        };
        uint16_t frag_all;
    };
#else
    union
    {
        struct
        {
            uint16_t reverse : 1; // 保留位,固定值为0
            uint16_t disable : 1; // 是否允许分片
            uint16_t more : 1;    // 后面有无其他分片包
            uint16_t offset : 13; // 分片数据包的偏移量
        };
        uint16_t frag_all;
    };
#endif

    uint8_t ttl;           // 生存时间
    uint8_t protocol;      // 协议
    uint16_t hdr_checksum; // 头部校验和
    uint8_t src_ip[IPV4_ADDR_SIZE];
    uint8_t dst_ip[IPV4_ADDR_SIZE];
    // 忽略选项
} ipv4_hdr_t;

// ipv4数据包结构
typedef struct _ipv4_pkt_t
{
    ipv4_hdr_t hdr;
    uint8_t data[1];
} ipv4_pkt_t;

#pragma pack()

net_err_t ipv4_init();
net_err_t ipv4_in(netif_t *netif, pktbuf_t *buf);
net_err_t ipv4_normal_in(netif_t *netif, pktbuf_t *buf, ipaddr_t *dst_ip, ipaddr_t *src_ip);
net_err_t ipv4_out(uint8_t protocol, ipaddr_t *dst_ip, ipaddr_t *src_ip, pktbuf_t *buf);

/**
 * @brief 根据收到的ipv4包获取报文头部长度
 */
static inline int ipv4_hdr_size(ipv4_pkt_t *pkt)
{
    return pkt->hdr.shdr * 4;
}

#endif